const express = require("express");
const app = express();
const bodyParser = require("body-parser");
// let ws = require("./websocket");
const cors = require("cors");
const process = require("process");
const path = require("path");
//开启gzip压缩
const compression = require("compression");
const crypto = require("crypto");
const config = require("./config");

const OpenAI = require("openai");
//deepseek-测试
const openai1 = new OpenAI({
  baseURL: "https://api.deepseek.com",
  apiKey: "sk-4bc1aa49d2634f1688deccf54ca351ab",
});

const { DWClient } = require("dingtalk-stream-sdk-nodejs");
const client = new DWClient({
  clientId: config.clientId,
  clientSecret: config.clientSecret,
});

let conversationHistory = [
  {
    role: "system",
    content: "请用100字内直接给出答案，无需解释，只需最终解决方案或配置。",
  },
];

// 发送消息到钉钉
async function sendDingDing(sessionWebhook, messageId, content) {
  // # 钉钉机器人的Webhook地址
  // var dingdingUrl = 'https://oapi.dingtalk.com/robot/send?access_token=73c2010c4fbddae889691d1cc8b439d2e79eb0ef85c15b610e1ce7edc63c5a36';
  var dingdingUrl = sessionWebhook;
  var secret =
    "SECf754c1f4c5d8c11e4ef5407bd894efb36a91213b15e03e77e4d46f640ab36038";

  var timestamp = new Date().getTime();
  var stringToSign = timestamp + "\n" + secret;
  var base = crypto
    .createHmac("sha256", secret)
    .update(stringToSign)
    .digest("base64");
  var sing = encodeURIComponent(base);
  var dingdingStr = dingdingUrl + `&timestamp=${timestamp}&sign=${sing}`;

  let link = "https://discipline.hibuilding.cn/unified-manage/mobile";
  // # 定义消息内容和被@的人（手机号码）
  at_mobiles = ["13856152714"]; // 被@人的手机号码
  let md = `### 🤖 Assistant-cy

---

**晁阳工作经历汇总**

---

### 一、浪潮集团

#### 1. 西部战区陆军通信网络综合管理系统（研发人员） **[^1]**

- **项目性质**：军事信息化管理系统（指挥专网承载）
- **核心技术**：MySQL/Oracle/MongoDB 数据库、Windows 任务调度
- **主要职责**：
  - 客户需求对接与方案确认
  - 系统部署与数据库搭建
  - 接口程序开发（基于 tyservice 平台）
  - 数据可视化前端开发（ECharts 应用）
  - 项目文档编撰（使用/维护手册）

#### 2. 药品器材监督管理系统（研发人员） **[^6]**

- **服务对象**：药品仪器监督检验总站（卫生局）
- **模块开发**：维修管理、退役报废功能
- **技术实现**：
  - 数据库表结构优化调整
  - 前后端接口开发调试
  - Bootstrap 框架应用

---

### 二、联想智慧医疗

#### 医院信息系统-药房管理模块（前端开发） **[^6]**

- **技术架构**：jQuery+BootStrap 技术栈
- **核心功能开发**：
  - 药品信息管理系统（剂量/产地等属性管理）
  - 药房资产数据可视化
  - Swagger API 对接与数据交互
- **协作流程**：
  - 需求测试与代码优化
  - 技术文档规范化审查
  - 跨部门问题协调支持

---

### 三、企业级平台项目

#### 1. Vue 平台管理系统迭代（前端负责人） **[^3]**

- **项目版本**：2.00-2.1.3 版本迭代
- **技术亮点**：
  - Vue CLI 脚手架搭建
  - Axios 数据交互驱动
  - Swiper 组件优化界面交互
- **管理职责**：
  - 需求评审与代码质量审查
  - UI/UX 持续优化跟踪
  - Tab 组件交互重构

#### 2. FaaS 平台（React 方向） **[^6]**

- **技术应用**：
  - Ant Design/G6 可视化库
  - 时序数据平台搭建
- **团队贡献**：
  - 技术分享会议主持
  - 新人项目搭建指导
  - CodeReview 全流程支持

---

### 四、个人项目

#### 网易云音乐 Demo（React 全栈） **[^5]**

- **技术实现**：
  - 仿官方 API 调用（CSRF 防御处理）
  - React-Swipeable 视图组件
  - http-proxy-middleware 跨域方案
- **开源地址**：https://gitee.com/cyapi/wyy

---

[^1]: 西部战区项目技术细节与职责描述
[^3]: Vue 平台管理系统的开发流程与技术应用
[^5]: 网易云音乐 demo 的技术实现方案
      [^6]: 药品监督系统与医院信息系统的开发职责及技术栈`;

  // # 消息内容（富文本格式）
  let markdown = {
    msgtype: "markdown",
    markdown: {
      title: "通知：",
      text:
        md ||
        `<font color="#FF0000">**通知：**</font>\n\n<font color="#0000FF">${content}</font>\n\n@${at_mobiles[0]}`,
    },
    at: {
      atMobiles: at_mobiles, // 被@人的手机号列表
      isAtAll: false, // 是否@所有人
    },
  };

  let text = {
    msgtype: "text",
    text: {
      content,
    },
    at: {
      atMobiles: at_mobiles,
      isAtAll: false,
    },
  };
  // 卡片消息内容
  const cardMessage = {
    msgtype: "actionCard", // 消息类型为卡片消息
    actionCard: {
      title: "这是一张行动卡片", // 卡片标题
      text: "测试", // 卡片正文
      hideAvatar: "0", // 是否隐藏头像，0表示显示，1表示隐藏
      btnOrientation: "0", // 按钮排列方向，0表示竖直，1表示水平
      singleTitle: "单个按钮示例", // 单个按钮的标题
      singleURL: "https://www.baidu.com", // 单个按钮的链接
    },
  };

  let feedCard = {
    msgtype: "feedCard",
    feedCard: {
      links: [
        {
          title: "卡片1标题",
          messageURL: link,
          picURL:
            "https://chaoyang-oss.oss-cn-hangzhou.aliyuncs.com/uploads/895f5145-dff4-4509-a852-36f267649b19",
        },
        {
          title: "卡片2标题",
          messageURL: link,
          picURL:
            "https://chaoyang-oss.oss-cn-hangzhou.aliyuncs.com/uploads/ce8e1bca7887fb654d6e44f2a9e4c29d.jpg",
        },
      ],
    },
  };

  let message = text;
  if (content == 2) {
    message = cardMessage;
  } else if (content == 3) {
    message = markdown;
  } else if (content == 4) {
    message = feedCard;
  } else {
    // 添加用户问题到历史
    conversationHistory.push({
      role: "user",
      content: `请用100字内直接给出答案，无需解释，只需最终解决方案或配置。问题：[${content}]`,
    });
    let obj = {
      messages: conversationHistory,
      model: "deepseek-chat",
      stream: false,
      temperature: 0.7, // 完全禁用随机性
    };
    //我想计算本次响应的耗时
    let startTime = new Date().getTime();
    const stream = await openai1.chat.completions.create(obj);

    // 计算耗时
    let endTime = new Date().getTime();
    let duration = endTime - startTime;

    // 添加模型回答到历史
    conversationHistory.push({
      role: "assistant",
      content: stream.choices[0]?.message?.content,
    });

    // 保留最近3轮对话（防止超出Token限制）
    if (conversationHistory.length > 7) {
      // system + 3轮(user+assistant)
      conversationHistory = [
        conversationHistory[0], // 保留system指令
        ...conversationHistory.slice(-6), // 保留最近3轮
      ];
    }

    message = {
      msgtype: "markdown",
      markdown: {
        title: "通知：",
        text:
          stream.choices[0]?.message?.content +
          `响应耗时：${duration / 1000} 秒`,
      },
      at: {
        atMobiles: at_mobiles, // 被@人的手机号列表
        isAtAll: false, // 是否@所有人
      },
    };
  }

  // # 发送消息quest写法
  var data = {
    json: message,
    encoding: "utf-8",
    headers: {
      "Content-Type": "application/json",
    },
  };

  //注意这里axios和fetch 发送post请求的区别---
  fetch(dingdingStr, {
    method: "POST",
    body: JSON.stringify(message), // 确保数据是 JSON 字符串
    headers: {
      "Content-Type": "application/json",
    },
    encoding: "utf-8",
  })
    .then((response) => {
      if (!response.ok) {
        throw new Error(`HTTP error! Status: ${response.status}`);
      }
    })
    .catch((error) => {
      // 处理错误
      console.error("发送消息失败:", error);
    });

  // request.post(dingdingStr, data, function (error, res, body) {
  //   if (!error && res.statusCode == 200) {
  //     console.log("body is ", body);
  //   }
  // });
}

// 注册回调监听
client
  .registerCallbackListener("/v1.0/im/bot/messages/get", async (res) => {
    try {
      const messageData = JSON.parse(res.data);
      const { messageId } = res?.headers;
      const { text, sessionWebhook } = messageData;
      // 打印关键信息用于调试
      console.log("关键参数:", messageData);
      // 使用消息ID进行去重处理
      if (sessionWebhook) {
        await sendDingDing(sessionWebhook, messageId, text?.content);
        // stream模式下，服务端推送消息到client后，会监听client响应，如果消息长时间未响应会在一定时间内(60s)重试推消息，
        // 可以通过此方法返回消息响应，避免多次接收服务端消息。
        client.onEvent(res);
        return { status: "SUCCESS" };
      } else {
        console.log("消息已处理或缺少sessionWebhook");
        return { status: "SUCCESS" };
      }
    } catch (error) {
      console.error("处理消息失败:", error);
      return { status: "LATER" }; // 处理失败时返回稍后重试状态
    }
  })
  .connect();

//获取token  https://oapi.dingtalk.com/gettoken?appkey=dinglj2ei6tpemgoojrm&appsecret=knIbM3ALFk_iNAolp6bkOFPsf6QASNAvrhGcHcCM1tOmKp7TjurGXo3SV3Z4C5sv
//  c6988700f2e3375d9c1f8021d4ccc130

// 使用compression中间件
app.use(compression());

// process 不需要引入直接使用即可
process.on("uncaughtException", (err) => {
  console.log("========");
  console.log(err);
  console.log("========");
});

process.on("unhandledRejection", (err) => {
  console.log("========");
  console.log(err);
  console.log("========");
});

// 如果没有unhandedRejection 这个错误不会被uncaughtException捕获
// new Promise((resolve, reject) => {
//   throw new Error('asd')
// })

//websocket
// ws(app);
// 使用 body-parser 中间件
app.use(bodyParser.json({ limit: "50mb" })); // 允许请求体最大为 50MB
app.use(bodyParser.urlencoded({ limit: "50mb", extended: true }));
app.use(bodyParser.json());

//跨域
app.all("*", function (req, res, next) {
  res.header("Access-Control-Allow-Origin", "*");
  res.header("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
  next();
});

app.use(
  cors({
    credentials: true,
    allowedHeaders: ["access_token", "Content-Type"],
  })
);

//使用routers:/api/xx
//引入user.js
const student = require("./routers/api/student");
const board = require("./routers/api/board");
// const img = require("./routers/api/img");
const openai = require("./routers/api/openai");
const third = require("./routers/api/third");
const dataSourceConfig = require("./routers/api/dataSourceConfig");
const moduleParams = require("./routers/api/module_params");
const sqlTemplates = require("./routers/api/sql_templates");
// const word = require("./routers/api/word");
app.use(express.static(path.join(__dirname, "dist")));
// 处理单页面应用的路由，返回index.html
app.get("/deepseek", (req, res) => {
  res.sendFile(path.join(__dirname, "html/openai.html"));
});
app.get("/sql", (req, res) => {
  res.sendFile(path.join(__dirname, "html/sql.html"));
});

//http://localhost:8888/api/student/xxx---xxx是router里的了
app.use("/api/student", student);
app.use("/api/board", board);
// app.use("/api/img", img);
app.use("/api/openai", openai);
app.use("/api/third", third);
app.use("/api/dataSourceConfig", dataSourceConfig);
app.use("/api/moduleParams", moduleParams);
app.use("/api/sqlTemplates", sqlTemplates);
// app.use("/api/word", word);
/*
 * $param
 * @return
 * @desc
 * */

app.listen(8888, function () {
  console.log("运行在8888端口");
});
